﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace ArkanoidX.Objects
{
    public class StatefulComponent : BaseComponent
    {
        public abstract class State<ObjT>
        {
            // Sprite size in pixels
            public Vector2 Size 
            { 
                get { return _size; }

                set
                {
                    _size = value;
                    _halfSize = _size * 0.5f;
                    RectInTarget = new Rectangle(0, 0, (int)(_size.X + 0.5f), (int)(_size.Y + 0.5f));
                }
            }

            public virtual Vector2 HalfSize { get { return _size / 2; } }

            // Rectangle in the texture
            public Rectangle RegionInSource { get { return RectInSource; } }

            public Texture2D Texture;
            public Rectangle RectInSource;
            public Rectangle RectInTarget;  // buffered value representing !!! SHARED BY METHODS !!!

            protected Vector2 _size;
            protected Vector2 _halfSize;
            protected Vector2 _srcHalfSize;

            public State(Texture2D texture, Vector2 size, Rectangle regionInSource)
            {
                Texture = texture;
                _size = size;
                RectInSource = regionInSource;

                _halfSize = new Vector2(_size.X * 0.5f, _size.Y * 0.5f);
                RectInTarget = new Rectangle(0, 0, (int)(_size.X + 0.5f), (int)(_size.Y + 0.5f));

                _srcHalfSize = new Vector2(regionInSource.Width * 0.5f, regionInSource.Y * 0.5f);
            }

            public float Width
            {
                get
                {
                    return _size.X;
                }

                set
                {
                    _size.X = value;
                    _halfSize.X = _size.X * 0.5f;
                    RectInTarget = new Rectangle(0, 0, (int)(_size.X + 0.5f), (int)(_size.Y + 0.5f));
                }
            }

            public float Height
            {
                get
                {
                    return _size.Y;
                }

                set
                {
                    _size.Y = value;
                    _halfSize.Y = _size.Y * 0.5f;
                    RectInTarget = new Rectangle(0, 0, (int)(_size.X + 0.5f), (int)(_size.Y + 0.5f));
                }
            }

            public State(Texture2D texture, Vector2 size)
                : this(texture, size, new Rectangle(0, 0, texture.Width, texture.Height))
            {
            }

            public State(Texture2D texture)
                : this(texture, new Vector2(texture.Width, texture.Height),
                       new Rectangle(0, 0, texture.Width, texture.Height))
            {
            }

            public virtual void Draw(SpriteBatch sBatch, Vector2 position, Color color)
            {
                // draw the sprite at specific position onto the batch
                position -= _halfSize;
                RectInTarget.X = (int)Math.Round(position.X);
                RectInTarget.Y = (int)Math.Round(position.Y);

                sBatch.Draw(Texture, RectInTarget, RectInSource, color);
            }

            public virtual void Draw(SpriteBatch sBatch, Vector2 position, Color color, float angle)
            {
                // draw the sprite at specific position onto the batch
                RectInTarget.X = (int)Math.Round(position.X);
                RectInTarget.Y = (int)Math.Round(position.Y - _halfSize.Y);

                sBatch.Draw(Texture, RectInTarget, RectInSource, color, angle, _srcHalfSize,
                       SpriteEffects.None, 0);
            }

            // Do update according to the state of the object
            public abstract void Update(ObjT obj, GameTime gameTime);

        }

        public StatefulComponent(Game game)
            : base(game)
        {
        }
    }

}
